Skip to content

buffer: Store potential resolved symlinks as AbsPath#3997

Open
JoeKar wants to merge 3 commits intomicro-editor:masterfrom
JoeKar:fix/symlinks
Open

buffer: Store potential resolved symlinks as AbsPath#3997
JoeKar wants to merge 3 commits intomicro-editor:masterfrom
JoeKar:fix/symlinks

Conversation

@JoeKar
Copy link
Copy Markdown
Member

@JoeKar JoeKar commented Feb 5, 2026

This will help us to keep track of the same file opened via different symlinks.

Fixes #3995

@dmaluka
Copy link
Copy Markdown
Collaborator

dmaluka commented Feb 10, 2026

I've noticed an "issue" with this PR. If we have a regular file foo and a symlink bar pointing to it, and we open bar in micro, the statusline shows its name is bar (not resolved). Ok, that is not a problem in itself. Then we open foo in another pane, and the statusline shows its name is bar too, not foo. Just because bar has been already opened, so its SharedBuffer already exists (and thus is reused by foo), and b.Path in this SharedBuffer is bar, not foo. Even though it is foo that is the original file, while bar is a symlink to it.

For comparison, vim shows the resolved file name in the statusline, so it behaves predictably: it always shows the original file name.

Well, maybe we can treat this as a feature ("first wins" rule)...

@JoeKar
Copy link
Copy Markdown
Member Author

JoeKar commented Feb 10, 2026

For comparison, vim shows the resolved file name in the statusline, so it behaves predictably: it always shows the original file name.

Well, maybe we can treat this as a feature ("first wins" rule)...

Hm, indeed...this behavior is somehow strange.
The order of opening the file shouldn't influence how it is named in the editor.
It should be every time the file name/path the user opened or the resolved path.

EDIT:
The more tricky thing is the (relative) path before the basename of the file (set basename false).

EDIT2:
Didn't find an elegant solution so far.

@dmaluka
Copy link
Copy Markdown
Collaborator

dmaluka commented Feb 11, 2026

Hmmmm... what is this? https://pkg.go.dev/path/filepath#EvalSymlinks :)

Worth checking if we can just use this?

Also, just realized: we should resolve each component of the path (i.e. each directory), not just the last one (the file itself), since any of the directories may be a symlink too?

And skimming through the code in https://github.com/golang/go/blob/master/src/path/filepath/symlink.go it looks like this filepath.EvalSymlinks() does resolve them all.

@JoeKar
Copy link
Copy Markdown
Member Author

JoeKar commented Feb 11, 2026

Hmmmm... what is this? https://pkg.go.dev/path/filepath#EvalSymlinks :)

Worth checking if we can just use this?

Whaaat...feels like this came out of nowhere. Don't know, why I didn't see this myself, especially since I had [filepath](the https://pkg.go.dev/path/filepath) documentation the last days open again.
But yes, definitely and it sounds promising, since it does exactly what we need.

Thank you for pointing me to this link!

@JoeKar JoeKar force-pushed the fix/symlinks branch 3 times, most recently from 9191df8 to a7840b2 Compare February 11, 2026 06:43
@dmaluka
Copy link
Copy Markdown
Collaborator

dmaluka commented Apr 6, 2026

I've noticed an "issue" with this PR. If we have a regular file foo and a symlink bar pointing to it, and we open bar in micro, the statusline shows its name is bar (not resolved). Ok, that is not a problem in itself. Then we open foo in another pane, and the statusline shows its name is bar too, not foo. Just because bar has been already opened, so its SharedBuffer already exists (and thus is reused by foo), and b.Path in this SharedBuffer is bar, not foo. Even though it is foo that is the original file, while bar is a symlink to it.

For comparison, vim shows the resolved file name in the statusline, so it behaves predictably: it always shows the original file name.

Hmm... I have no idea why I thought vim always showed the original file name. Now I clearly see that vim shows the name of whatever file was opened first (i.e. just like micro did in that early version of this PR).

And actually I see nothing wrong with this behavior.

So we can just do that, and thus keep the code simpler (as we will only need to resolve the absolute path, not the relative one)?

@JoeKar
Copy link
Copy Markdown
Member Author

JoeKar commented Apr 8, 2026

So we can just do that, and thus keep the code simpler (as we will only need to resolve the absolute path, not the relative one)?

If this is the more desired and predictable behavior, then yes...sure.

JoeKar added 3 commits April 8, 2026 16:17
Otherwise it will be removed async, which shouldn't happen in case there is
still one buffer open with the same modified file.
Otherwise we unnecessarily serialize the shared buffer every time when closing
a bufpane with this buffer, so every such serialize overwrites the previous one,
thus only the last serialize (when closing the last instance of the buffer, i.e.
when actually closing the file, i.e. when the buffer is not shared anymore) will
be used anyway.
Otherwise we can't identify if we have the same file open multiple times via
different symlinks.
The test must be adapted to resolve symlinks in `findBuffer()`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Different saveundo buffers for symlinked files

2 participants